#include <emmintrin.h>
#include <smmintrin.h>
#include <xmmintrin.h>
#include "game_intrinsicts.h"
#include "game_debug.h"
#include "game_render_group.h"
#include "game_config.h"
#include "game_sort.h"

struct push_buffer_result {
    sort_sprite_bound *SortEntry;
    render_group_entry_header *Header;
};

push_buffer_result PushBuffer(render_group *Group, uint32 SortEntryCount, uint32 Size) {
    push_buffer_result Result = {};
    game_render_commands *Commands = Group->Commands;
    // 增加 header 的大小到实际的元素大小
    sort_sprite_bound *SpriteBounds = GetSortEntries(Commands);

    // 检查是否有足够的空间在 PushBuffer 中存储新的元素
    if ((uint8 *)(SpriteBounds + (Commands->SortEntryCount + SortEntryCount)) <=
        (Commands->PushBufferDataAt - Size)) {
        Commands->PushBufferDataAt -= Size;
        Result.Header = (render_group_entry_header *)Commands->PushBufferDataAt;
        Result.SortEntry = SpriteBounds + Commands->SortEntryCount;
        Commands->SortEntryCount += SortEntryCount;
    } else {
        // 如果没有足够的空间，触发错误路径
        InvalidCodePath;
    }

    return Result;
}

void PushSortBarrier(render_group *RenderGroup, bool32 TurnOffSorting) {
    push_buffer_result Push = PushBuffer(RenderGroup, 1, 0);
    if (Push.SortEntry) {
        Push.SortEntry->Offset = SPRITE_BARRIER_OFFSET_VALUE;
        Push.SortEntry->Flags = TurnOffSorting ? Sprite_BarrierTurnsOffSorting : 0;
    }
}

uint16 ReserveSortKey(render_group *RenderGroup) {
    game_render_commands *Commands = RenderGroup->Commands;
    Assert(Commands->LastUsedManualSortkey < Uint16Maximum);
    uint16 Result = (uint16)++Commands->LastUsedManualSortkey;
    return Result;
}

render_group BeginRenderGroup(game_assets *Assets, game_render_commands *Commands,
                              uint32 GenerationID, bool32 RendersInBackground, int32 PixelWidth,
                              int32 PixelHeight) {
    render_group Result = {};

    Result.Assets = Assets;
    Result.RendersInBackground = RendersInBackground;
    Result.Commands = Commands;
    Result.GenerationID = GenerationID;
    Result.MissingResourceCount = 0;
    Result.ScreenArea = RectMinDim(v2{0, 0}, v2i(PixelWidth, PixelHeight));
    Result.CurrentClipRectIndex = PushClipRect(&Result, 0, 0, PixelWidth, PixelHeight, 0);
    return Result;
}

void Perspective(render_group *RenderGroup, real32 MetersToPixels, real32 FocalLength,
                 real32 DistanceAboveTarget) {
    real32 PixelsToMeters = SafeRatio1(1.0f, MetersToPixels);
    int32 PixelWidth = (int32)GetDim(RenderGroup->ScreenArea).x;
    int32 PixelHeight = (int32)GetDim(RenderGroup->ScreenArea).y;

    RenderGroup->MonitorHalfDimInMeters = 0.5f * v2{PixelWidth * PixelsToMeters,  //
                                                    PixelHeight * PixelsToMeters};

    RenderGroup->CameraTransform.MetersToPixels = MetersToPixels;
    RenderGroup->CameraTransform.DistanceAboveTarget = DistanceAboveTarget;  // 10.0f;

    RenderGroup->CameraTransform.FocalLength = FocalLength;  // 0.6f;  // 人坐在显示器前的距离（米）
    RenderGroup->CameraTransform.ScreenCenter = v2{0.5f * PixelWidth,  //
                                                   0.5f * PixelHeight};
    RenderGroup->CameraTransform.Orthographic = false;
}

void Orthographic(render_group *RenderGroup, int32 PixelWidth, int32 PixelHeight,
                  real32 MetersToPixels, real32 DistanceAboveTarget, real32 FocalLength) {
    real32 PixelsToMeters = SafeRatio1(1.0f, MetersToPixels);
    (void)PixelsToMeters;
    RenderGroup->MonitorHalfDimInMeters = 0.5f * v2{PixelWidth * PixelsToMeters,  //
                                                    PixelHeight * PixelsToMeters};

    RenderGroup->CameraTransform.MetersToPixels = MetersToPixels;
    RenderGroup->CameraTransform.DistanceAboveTarget = DistanceAboveTarget;  // 1.0f;

    RenderGroup->CameraTransform.FocalLength = FocalLength;  // 0.6f;  // 人坐在显示器前的距离（米）
    RenderGroup->CameraTransform.ScreenCenter = v2{0.5f * PixelWidth,  //
                                                   0.5f * PixelHeight};
    RenderGroup->CameraTransform.Orthographic = true;
}

struct bilinear_sample {
    uint32 A, B, C, D;
};

bilinear_sample BilinearSample(loaded_bitmap *Texture, int32 X, int Y) {
    bilinear_sample Result;

    // 获取纹理内存中的起始地址并计算Texel的指针
    uint8 *TexelPtr = ((uint8 *)Texture->Memory) +  // 获取纹理内存的起始位置
                      Y * Texture->Pitch +          // 计算y位置偏移
                      X * sizeof(uint32);  // 计算x位置偏移（每个纹素的大小是uint32）

    Result.A = *(uint32 *)TexelPtr;
    Result.B = *(uint32 *)(TexelPtr + sizeof(uint32));
    Result.C = *(uint32 *)(TexelPtr + Texture->Pitch);
    Result.D = *(uint32 *)(TexelPtr + Texture->Pitch + sizeof(uint32));

    return Result;
}
v4 SRGBBilinearBlend(bilinear_sample TexelSample, real32 fX, real32 fY) {
    // 解包 TexelSample 中的四个颜色值 (A, B, C, D) 为线性颜色值
    v4 TexelA = Unpack4x8(TexelSample.A);
    v4 TexelB = Unpack4x8(TexelSample.B);
    v4 TexelC = Unpack4x8(TexelSample.C);
    v4 TexelD = Unpack4x8(TexelSample.D);

    // 注意：从 sRGB 色彩空间转换到线性亮度空间
    TexelA = SRGB255ToLinear1(TexelA);  // 转换 TexelA
    TexelB = SRGB255ToLinear1(TexelB);  // 转换 TexelB
    TexelC = SRGB255ToLinear1(TexelC);  // 转换 TexelC
    TexelD = SRGB255ToLinear1(TexelD);  // 转换 TexelD

    // 根据 alpha 值调整 RGB 分量
    TexelA.rgb *= TexelA.a;  // 按照 TexelA 的 alpha 调整 RGB
    TexelB.rgb *= TexelA.a;  // 按照 TexelA 的 alpha 调整 RGB
    TexelC.rgb *= TexelA.a;  // 按照 TexelA 的 alpha 调整 RGB
    TexelD.rgb *= TexelA.a;  // 按照 TexelA 的 alpha 调整 RGB

    // 进行线性插值：首先根据 fx 在 TexelA 和 TexelB 之间进行插值，
    // 然后根据 fx 在 TexelC 和 TexelD 之间进行插值，得到两组插值结果
    // 最后根据 fy 在两组插值结果之间进行插值
    v4 Result =
        Lerp(Lerp(TexelA, fX, TexelB),  // 基于 fx 对 TexelA 和 TexelB 进行插值
             fY,  // 使用 fy 对第一阶段的插值结果进行进一步插值
             Lerp(TexelC, fX, TexelD));  // 基于 fx 对 TexelC 和 TexelD 进行插值，并与 fy 进行插值

    return Result;  // 返回最终插值结果
}

v3 SampleEnvironmentMap(v2 ScreenSpaceUV, v3 SampleDirection, real32 Roughness,
                        environment_map *Map,  //
                        real32 DistanceFromMapInz) {
    /*
        ScreenSpaceUV 告诉我们光线是从哪里发射的，以标准化的屏幕坐标表示。
        SampleDirection 告诉我们光线传播的方向，预计应该是标准化的。
        Roughness 表示我们从地图中采样的是哪个 LOD（细节层次）。
    */
    // 根据粗糙度 (Roughness) 计算适当的 LOD 索引，用于选择环境贴图的细节层次
    uint32 LODIndex = (uint32)(Roughness * (real32)(ArrayCount(Map->LOD) - 1) + 0.5f);
    Assert(LODIndex < ArrayCount(Map->LOD));   // 确保计算出的 LOD 索引在有效范围内
    loaded_bitmap *LOD = &Map->LOD[LODIndex];  // 获取对应 LOD 层级的环境贴图

    // 每米的 UV 单位数，决定了每米与 UV 坐标的转换比例
    real32 UVsPerMeter = 0.1f;

    // 计算一个系数 C，用来将米转换为 UV 坐标，并考虑采样方向的 Y 分量
    real32 C = (UVsPerMeter * DistanceFromMapInz) / SampleDirection.y;

    // 使用该系数计算偏移量，偏移量是与 X 和 Z 方向的采样方向成比例的
    v2 Offset = C * v2{SampleDirection.x, SampleDirection.z};

    // 计算最终的 UV 坐标，将屏幕空间 UV 和偏移量相加
    v2 UV = ScreenSpaceUV + Offset;

    // 限制 UV 坐标在 [0, 1] 范围内，以避免采样越界
    UV.x = Clamp01(UV.x);
    UV.y = Clamp01(UV.y);

    // 计算纹理坐标 tx 和 ty，先根据 U 和 V 计算出它们在纹理中的位置。
    // U 和 V 是相对坐标，计算时需要将它们映射到纹理的宽度和高度，减去 2 是为了防止采样超出边界。
    real32 tx = ((UV.x * (real32)(LOD->Width - 2)));   // 计算 tx 坐标（X方向）
    real32 ty = ((UV.y * (real32)(LOD->Height - 2)));  // 计算 ty 坐标（Y方向）

    // 获取整数部分 x 和 y，并计算它们的浮动部分 fx 和 fy
    int32 x = (int32)tx;         // 获取纹理 X 坐标的整数部分
    int32 y = (int32)ty;         // 获取纹理 Y 坐标的整数部分
    real32 fx = tx - (real32)x;  // 计算纹理 X 坐标的浮动部分
    real32 fy = ty - (real32)y;  // 计算纹理 Y 坐标的浮动部分

    // 确保 x 和 y 在纹理的有效范围内，避免超出纹理边界
    Assert((x >= 0) && (x <= LOD->Width));   // 断言 x 在纹理宽度范围内
    Assert((y >= 0) && (y <= LOD->Height));  // 断言 y 在纹理高度范围内
    if (Global_Renderer_ShowLightingSamples) {
        // 在纹理上显示采样
        uint8 *TexelPtr = (uint8 *)LOD->Memory + y * LOD->Pitch + x * sizeof(uint32);
        *(uint32 *)TexelPtr = 0xFFFFFFFF;
    }
    // 获取纹理的双线性采样结果
    bilinear_sample Sample = BilinearSample(LOD, x, y);

    // 进行线性插值，获取最终的环境映射结果，并返回颜色的 RGB 分量
    v3 Result = SRGBBilinearBlend(Sample, fx, fy).xyz;

    return Result;  // 返回最终的环境映射结果
}

struct counts {
    int mm_set1_ps;
    int mm_add_ps;
    int mm_sub_ps;
    int mm_mul_ps;
    int mm_castps_si128;
    int mm_and_ps;
    int mm_or_ps;
    int mm_or_si128;
    int mm_cmpge_ps;
    int mm_cmple_ps;
    int mm_min_ps;
    int mm_max_ps;
    int mm_cvttps_epi32;
    int mm_cvtps_epi32;
    int mm_cvtepi32_ps;
    int mm_and_si128;
    int mm_andnot_si128;
    int mm_srli_epi32;
    int mm_slli_epi32;
    int mm_sqrt_ps;
    int mm_movemask_epi8;
    int mm_unpackhi_epi32;
    int mm_unpacklo_epi32;
};

// 渲染一个矩形区域
internal void DrawRectangleSlowly(loaded_bitmap *Buffer, v2 Origin, v2 XAxis, v2 YAxis, v4 Color,
                                  loaded_bitmap *Texture,    //
                                  loaded_bitmap *NormalMap,  //
                                  environment_map *Top,      //
                                  environment_map *Middle,   //
                                  environment_map *Bottom,   //
                                  real32 PixelsToMeters) {
    // 计算X轴和Y轴的长度
    real32 XAxisLength = Length(XAxis);
    real32 YAxisLength = Length(YAxis);

    // 计算标准化的X轴系数NxAxis
    // 使用X轴长度与Y轴长度的比值来调整X轴的比例
    v2 NxAxis = XAxisLength / YAxisLength * XAxis;

    // 计算标准化的Y轴系数NyAxis
    // 使用Y轴长度与X轴长度的比值来调整Y轴的比例
    v2 NyAxis = YAxisLength / XAxisLength * YAxis;
    // 计算Z轴的缩放因子NzScale，基于X轴和Y轴的长度
    // 这里使用X轴和Y轴长度的平均值来平衡Z轴的大小
    (void)NxAxis;
    (void)NyAxis;
    real32 NzScale = 0.5f * (XAxisLength + YAxisLength);

    // 计算 X 轴的平方长度的倒数，避免每次计算平方根
    real32 InvXAxisLengthSq = 1.0f / LengthSq(XAxis);

    // 计算 Y 轴的平方长度的倒数，避免每次计算平方根
    real32 InvYAxisLengthSq = 1.0f / LengthSq(YAxis);

    (void)NormalMap;
    (void)Middle;
    uint32 Color32 =
        (uint32)((RoundReal32ToInt32(Color.a * 255.0f) << 24) |
                 (RoundReal32ToUInt32(Color.r * 255.0f)
                  << 16) |  // 将 R
                            // 颜色值乘以255并四舍五入，然后左移16位，放到高8位（RR部分）
                 (RoundReal32ToUInt32(Color.g * 255.0f)
                  << 8) |  // 将 G
                           // 颜色值乘以255并四舍五入，然后左移8位，放到中间8位（GG部分）
                 (RoundReal32ToUInt32(Color.b * 255.0f)
                  << 0));  // 将 B 颜色值乘以255并四舍五入，放到低8位（BB部分）

    // 获取缓冲区的最大宽度和最大高度
    int WidthMax = Buffer->Width - 1;
    int HeightMax = Buffer->Height - 1;

    real32 InvWidthMax = 1.0f / (real32)WidthMax;
    real32 InvHeightMax = 1.0f / (real32)HeightMax;

    real32 OriginZ = 0.0f;
    // 设置原点的Z坐标为0，假设原点在平面上，Z值不变
    real32 OriginY = (Origin + 0.5f * XAxis + 0.5f * YAxis).y;
    // 计算原点Y坐标，通过添加X轴和Y轴的分量来调整原点位置
    real32 FixedCastY = InvHeightMax * OriginY;
    // 使用归一化的高度值调整原点Y坐标，FixedCastY表示调整后的Y坐标

    // 初始化最小和最大值，分别用于 X 和 Y 轴
    int XMin = WidthMax;
    int XMax = 0;
    int YMin = HeightMax;
    int YMax = 0;

    // 定义四个测试点，表示矩形的四个角
    v2 P[4] = {Origin, Origin + XAxis, Origin + XAxis + YAxis, Origin + YAxis};

    // 遍历四个点，计算其对应的地板值和天花板值
    for (uint32 PIndex = 0; PIndex < ArrayCount(P); PIndex++) {
        v2 TestP = P[PIndex];

        // 获取当前点的地板值和天花板值，分别用于 X 和 Y 轴
        int FloorX = FloorReal32ToInt32(TestP.x);
        int CeilX = CeilReal32ToInt32(TestP.x);
        int FloorY = FloorReal32ToInt32(TestP.y);
        int CeilY = CeilReal32ToInt32(TestP.y);

        // 更新 XMin 和 XMax，确保 XMin 是所有点的最小 X 值，XMax 是最大 X 值
        if (XMin > FloorX) {
            XMin = FloorX;
        }
        if (XMax < CeilX) {
            XMax = CeilX;
        }

        // 更新 YMin 和 YMax，确保 YMin 是所有点的最小 Y 值，YMax 是最大 Y 值
        if (YMin > FloorY) {
            YMin = FloorY;
        }
        if (YMax < CeilY) {
            YMax = CeilY;
        }
    }

    // 确保 XMin 和 YMin 不小于 0，避免越界
    if (XMin < 0) {
        XMin = 0;
    }
    if (YMin < 0) {
        YMin = 0;
    }

    // 确保 XMax 和 YMax 不超过缓冲区的宽度和高度
    if (XMax > WidthMax) {
        XMax = WidthMax;
    }
    if (YMax > HeightMax) {
        YMax = HeightMax;
    }

    // 计算起始行的位置，用于将数据写入缓冲区
    uint8 *Row = ((uint8 *)Buffer->Memory + XMin * BITMAP_BYTES_PER_PIEXLE + YMin * Buffer->Pitch);

    // 遍历矩形区域的每一行（从MinY到MaxY）
    for (int Y = YMin; Y <= YMax; ++Y) {
        // 当前行的起始地址，Pixel是指向当前行的像素数据指针
        uint32 *Pixel = (uint32 *)Row;

        // 遍历当前行的每一个像素（从MinX到MaxX）
        for (int X = XMin; X <= XMax; ++X) {
#if 1
            // 创建当前像素位置的 v2 坐标
            v2 PixelP = v2i(X, Y);

            v2 d = PixelP - Origin;

            // 计算四个边的点积结果，用于判断当前像素是否位于形状内部
            real32 Edge0 = Inner(d, -Perp(XAxis));
            // 第一个边：原点到像素点与X轴的负方向垂直向量的内积
            real32 Edge1 = Inner(d - XAxis, -Perp(YAxis));
            // 第二个边：(Origin + XAxis) 到像素点与Y轴的负方向垂直向量的内积
            real32 Edge2 = Inner(d - XAxis - YAxis, Perp(XAxis));
            // 第三个边：(Origin + XAxis + YAxis) 到像素点与X轴的正方向垂直向量的内积
            real32 Edge3 = Inner(d - YAxis, Perp(YAxis));
            // 第四个边：(Origin + YAxis) 到像素点与Y轴的正方向垂直向量的内积

            real32 ZDiff = 0;

            // 如果四个边的点积结果都小于 0，表示该像素位于形状内部
            if ((Edge0 < 0) &&  //
                (Edge1 < 0) &&  //
                (Edge2 < 0) &&  //
                (Edge3 < 0)) {
#if 0
                v2 ScreenSpaceUV = {InvWidthMax * X, FixedCastY};
#else

                (void)InvWidthMax;
                (void)FixedCastY;
                v2 ScreenSpaceUV = {0.0f, 0.0f};
                (void)ScreenSpaceUV;
#endif
                // 计算Z轴差异（ZDiff），通过将Y坐标与原点Y坐标的差值转换为世界空间中的Z差异。
                // 先计算Y与原点Y坐标的差异，然后乘以像素到米的转换因子（PixelToMeters），
                // 以便将其从像素空间转换为实际的世界空间（米）高度差异。
                ZDiff = PixelsToMeters * ((real32)Y - OriginY);
                (void)ZDiff;

                // 计算U和V坐标，它们代表了在纹理中的位置，基于d和X轴、Y轴的内积
                real32 U = InvXAxisLengthSq * Inner(d, XAxis);
                // U坐标，基于d和X轴的内积，乘以反向X轴的长度平方
                real32 V = InvYAxisLengthSq * Inner(d, YAxis);
                // V坐标，基于d和Y轴的内积，乘以反向Y轴的长度平方

#if 0
                // 确保U和V都在[0, 1]范围内
                Assert((U >= 0.0f) && (U <= 1.0f));  // 断言U在0到1之间
                Assert((V >= 0.0f) && (V <= 1.0f));  // 断言V在0到1之间
#endif
                // 根据U和V计算纹理坐标，tx和ty是浮动的坐标值
                real32 tx = ((U * (real32)(Texture->Width - 2)));   // 计算纹理X坐标
                real32 ty = ((V * (real32)(Texture->Height - 2)));  // 计算纹理Y坐标

                // 获取整数坐标x和y，并计算出它们的浮动部分fx和fy
                int32 x = (int32)tx;         // 获取纹理的X坐标整数部分
                int32 y = (int32)ty;         // 获取纹理的Y坐标整数部分
                real32 fx = tx - (real32)x;  // 计算纹理X坐标的浮动部分
                real32 fy = ty - (real32)y;  // 计算纹理Y坐标的浮动部分

                // 确保x和y在纹理的有效范围内
                Assert((x >= 0) && (x <= Texture->Width));   // 断言x在纹理宽度范围内
                Assert((y >= 0) && (y <= Texture->Height));  // 断言y在纹理高度范围内

                bilinear_sample TexelSample = BilinearSample(Texture, x, y);
                v4 Texel = SRGBBilinearBlend(TexelSample, fx, fy);
#if 0
                if (NormalMap) {
                    bilinear_sample NormalSample = BilinearSample(NormalMap, x, y);

                    v4 NormalA = Unpack4x8(NormalSample.A);
                    v4 NormalB = Unpack4x8(NormalSample.B);
                    v4 NormalC = Unpack4x8(NormalSample.C);
                    v4 NormalD = Unpack4x8(NormalSample.D);

                    // 进行线性插值：首先插值TexelA和TexelB，基于fx的值，然后再插值TexelC和TexelD，基于fx的值
                    // 这一步得到的是两组插值结果，其中每一组的插值根据fx进行
                    v4 Normal = Lerp(Lerp(NormalA, fx, NormalB),  // 根据fx对TexelA和TexelB进行插值
                                     fy,  // 使用fy值对上一阶段的插值结果进行进一步插值
                                     Lerp(NormalC, fx, NormalD));
                    // 根据fx对TexelC和TexelD进行插值，然后与fy进行插值

                    // 调用 UnscaleAndBiasNormal 函数对法线进行解压缩和缩放，将其从[0,
                    // 255]范围转换为[-1, 1]范围，并处理粗糙度
                    Normal = UnscaleAndBiasNormal(Normal);
                    // 变换x y轴法向量跟着变换
                    // n_x * |y|/|x| *  x
                    // n_y * |x|/|y| *  y
                    // 更新法线的xy分量，使用NxAxis和NyAxis来调整原始法线的xy部分
                    Normal.xy = Normal.x * NxAxis + Normal.y * NyAxis;

                    // 更新法线的z分量，应用NzScale缩放因子调整Z分量
                    Normal.z *= NzScale;
                    Normal.xyz = Normalize(Normal.xyz);

                    // 注意：眼睛向量始终假设为 [0, 0, 1]
                    // 这是反射公式的简化版本： -e + 2(e·I) N
                    // 定义眼睛向量，假设始终指向屏幕外的正Z轴方向
                    v3 EyeVector = {0, 0, 1};

                    // 计算反射方向，公式：2 * Normal.z * Normal.xyz
                    // 这里利用法线的Z分量来调整反射方向
                    v3 BounceDirection = 2.0f * Normal.z * Normal.xyz;

                    // 调整反射方向的Z分量，减去1，完成反射计算
                    BounceDirection.z -= 1.0f;

                    BounceDirection.z = -BounceDirection.z;
                    // 对法线进行缩放和偏移处理
                    environment_map *FarMap = 0;

                    real32 Pz = OriginZ + ZDiff;

                    // 定义一个浮动类型变量，表示从地图的 z 轴方向的距离，初始值为 1.0f。
                    // real32 MapZ = 1.0f;

                    // 将反弹方向的Y分量赋值给tEnvMap，tEnvMap用于表示环境映射采样的方向。
                    // 通过使用反弹方向的Y分量，可以确保采样方向正确，并避免直接处理法线方向。
                    // tEnvMap 将作为采样环境地图时的方向输入，控制采样朝向。
                    real32 tEnvMap = BounceDirection.y;

                    // 获取法线的y分量,用于判断对应的环境贴图
                    real32 tFarMap = 0.0f;

                    // 根据法线的y分量选择合适的环境贴图
                    if (tEnvMap < -0.5f) {
                        FarMap = Bottom;
                        // 如果法线朝下，则选择底部环境贴图
                        tFarMap = -1.0f - 2.0f * tEnvMap;
                        // 计算插值系数，用于混合

                    } else if (tEnvMap > 0.5f) {
                        FarMap = Top;
                        // 如果法线朝上，则选择顶部环境贴图
                        tFarMap = 2.0f * (tEnvMap - 0.5f) / 0.5f;
                        // 计算插值系数，用于混合
                    }

                    // 初始化光照颜色
                    v3 LightColor = {
                        0, 0,
                        0};  // SampleEnvironmentMap(ScreenSpaceUV, Normal.xyz, Normal.z, Middle);
                    // 默认光照颜色为黑色

                    // 如果选择了合适的环境贴图，则采样该贴图的颜色并进行插值
                    if (FarMap) {
                        real32 DistanceFromMapInZ = FarMap->Pz - Pz;

                        v3 FarMapColor = SampleEnvironmentMap(ScreenSpaceUV, BounceDirection,
                                                              Normal.w, FarMap, DistanceFromMapInZ);
                        // 从环境贴图中采样颜色
                        LightColor = Lerp(LightColor, tFarMap, FarMapColor);
                        // 将采样到的颜色与原光照颜色进行插值
                    }

                    // 根据光照颜色修改纹理的颜色值
                    Texel.rgb = Texel.rgb + Texel.a * LightColor;
#if 0
                    // 将光照影响加到原始纹理的颜色上
                    Texel.rgb = v3{0.5f, 0.5f, 0.5f} + 0.5f * BounceDirection;
                    Texel.rgb *= Texel.a;
#endif
                }
#endif
                (void)Bottom;
                (void)Top;
                (void)OriginZ;
                (void)NzScale;
                // 对纹理颜色进行颜色分量逐项相乘，调整亮度
                Texel = Hadamard(Texel, Color);
                // Hadamard 函数执行逐项乘法

                // 将颜色值限制在[0, 1]区间内
                Texel.r = Clamp01(Texel.r);
                // 限制红色通道的值
                Texel.g = Clamp01(Texel.g);
                // 限制绿色通道的值
                Texel.b = Clamp01(Texel.b);
                // 限制蓝色通道的值

                v4 Dest = {// 获取目标像素的红色通道值
                           (real32)((*Pixel >> 16) & 0xFF),
                           // 获取目标像素的绿色通道值
                           (real32)((*Pixel >> 8) & 0xFF),
                           // 获取目标像素的蓝色通道值
                           (real32)((*Pixel >> 0) & 0xFF),
                           // 获取目标像素的Alpha通道值
                           (real32)((*Pixel >> 24) & 0xFF)};
                // 注意：从sRGB转换到线性亮度空间
                Dest = SRGB255ToLinear1(Dest);

                v4 Blended = (1.0f - Texel.a) * Dest + Texel;
#if 0
                {
                    // 根据Alpha通道值进行颜色混合，使用源像素和目标像素的红色通道
                    InvRSA * Dest.r + Texel.r,
                    // 计算混合后的红色通道值
                    // 使用源像素和目标像素的绿色通道进行颜色混合
                    InvRSA * Dest.g + Texel.g,
                    // 计算混合后的绿色通道值
                    // 使用源像素和目标像素的蓝色通道进行颜色混合
                    InvRSA * Dest.b + Texel.b,  // 计算混合后的蓝色通道值
                    InvRSA * Dest.a + Texel.a   // 计算混合后的Alpha值
                };
#endif
                // 注意：从线性亮度空间到sRGB转换
                v4 Blended255 = Linear1ToSRGB255(Blended);

                // 将混合后的RGB值合并为一个32位整数并保存到目标像素中，经过四舍五入
                *Pixel =
                    (((uint32)(Blended255.a + 0.5f) << 24)  //
                     | ((uint32)(Blended255.r + 0.5f) << 16)  // 将红色通道值放到目标像素的红色位置
                     | ((uint32)(Blended255.g + 0.5f) << 8)  // 将绿色通道值放到目标像素的绿色位置
                     | ((uint32)(Blended255.b + 0.5f) << 0));  // 将蓝色通道值放到目标像素的蓝色位置
                (void)Color32;
            }
#else
            *Pixel = Color32;  // 将颜色赋给当前像素并移动指针
#endif
            ++Pixel;
        }
        // 跳到下一行的起始地址
        Row += Buffer->Pitch;  // 根据图像的每行的字节数跳到下一行
    }
    uint32 PixelCount = 0;
    if ((XMax > XMin) && (YMax > YMin)) {
        PixelCount = (XMax - XMin - 1) * (YMax - YMin + 1) / 2;
        (void)PixelCount;
    }
}
// #pragma optimize("", off)

internal void DrawMatte(loaded_bitmap *Buffer,                              //
                        loaded_bitmap *Bitmap, real32 RealX, real32 RealY,  //
                        real32 CAlpha = 1.0f) {
    // 计算位图在缓冲区中绘制的像素对齐矩形坐标
    int32 MinX = RoundReal32ToInt32(RealX);  // 位图的左边界
    int32 MinY = RoundReal32ToInt32(RealY);  // 位图的上边界
    int32 MaxX = MinX + Bitmap->Width;       // 位图的右边界
    int32 MaxY = MinY + Bitmap->Height;      // 位图的下边界

    int32 SourceOffsetY = 0;
    int32 SourceOffsetX = 0;
    // 将计算的矩形坐标限制在缓冲区边界内
    if (MinX < 0) {
        SourceOffsetX = -MinX;
        MinX = 0;  // 防止越过缓冲区左边界
    }
    if (MinY < 0) {
        SourceOffsetY = -MinY;
        MinY = 0;  // 防止越过缓冲区上边界
    }
    if (MaxX > Buffer->Width) {
        MaxX = Buffer->Width;  // 防止越过缓冲区右边界
    }
    if (MaxY > Buffer->Height) {
        MaxY = Buffer->Height;  // 防止越过缓冲区下边界
    }

    // Bitmap->Pitch * (Bitmap->Height - 1)
    //  获取位图数据的指针
    //  注意：位图数据是从底部开始存储的，因此从最后一行开始读取
    uint8 *SourceRow = (uint8 *)Bitmap->Memory + Bitmap->Pitch * SourceOffsetY +
                       BITMAP_BYTES_PER_PIEXLE * SourceOffsetX;
    // 获取缓冲区内存的指针，从绘制起点(MinX, MinY)开始
    // 缓冲区的内存布局是线性的，因此需要根据每行的跨度(Pitch)和像素大小计算起始位置
    uint8 *DestRow =
        ((uint8 *)Buffer->Memory + MinX * BITMAP_BYTES_PER_PIEXLE + MinY * Buffer->Pitch);

    // 遍历裁剪后的矩形区域中的每一行
    for (int32 Y = MinY; Y < MaxY; ++Y) {
        uint32 *Dest = (uint32 *)DestRow;      // 目标缓冲区当前行的指针
        uint32 *Source = (uint32 *)SourceRow;  // 源位图当前行的指针

        // 遍历当前行的每一列
        // 遍历从 MinX 到 MaxX 的每个像素
        for (int32 X = MinX; X < MaxX; ++X) {
            // 获取源像素的Alpha通道值（范围0-255）
            real32 SA = ((real32)((*Source >> 24) & 0xFF));

#if 0
            // 获取源像素的红色通道值
            real32 SR = CAlpha * (real32)((*Source >> 16) & 0xFF);
            // 获取源像素的绿色通道值
            real32 SG = CAlpha * (real32)((*Source >> 8) & 0xFF);
            // 获取源像素的蓝色通道值
            real32 SB = CAlpha * (real32)((*Source >> 0) & 0xFF);
#endif
            // 将Alpha值归一化到[0, 1]之间
            real32 RSA = (SA / 255.0f) * CAlpha;  // 归一化后的源像素Alpha值

            // 获取目标像素的Alpha通道值
            real32 DA = (real32)((*Dest >> 24) & 0xFF);
            // 获取目标像素的红色通道值
            real32 DR = (real32)((*Dest >> 16) & 0xFF);
            // 获取目标像素的绿色通道值
            real32 DG = (real32)((*Dest >> 8) & 0xFF);
            // 获取目标像素的蓝色通道值
            real32 DB = (real32)((*Dest >> 0) & 0xFF);
            // 将目标像素的Alpha值归一化到[0, 1]之间
            // real32 RDA = (DA / 255.0f);

            // 计算源和目标像素的Alpha值加权
            real32 InvRSA = (1.0f - RSA);  // 源像素Alpha的反值
            // real32 A = 255.0f * (RSA + RDA - RSA * RDA);  // 计算混合后的Alpha值

            real32 A = InvRSA * DA;
            // 根据Alpha通道值进行颜色混合，使用源像素和目标像素的红色通道
            real32 R = InvRSA * DR;  // 计算混合后的红色通道值
            // 使用源像素和目标像素的绿色通道进行颜色混合
            real32 G = InvRSA * DG;  // 计算混合后的绿色通道值
            // 使用源像素和目标像素的蓝色通道进行颜色混合
            real32 B = InvRSA * DB;  // 计算混合后的蓝色通道值

            // 将混合后的RGB值合并为一个32位整数并保存到目标像素中，经过四舍五入
            *Dest = (((uint32)(A + 0.5f) << 24)  //
                     | ((uint32)(R + 0.5f) << 16)  // 将红色通道值放到目标像素的红色位置
                     | ((uint32)(G + 0.5f) << 8)  // 将绿色通道值放到目标像素的绿色位置
                     | ((uint32)(B + 0.5f) << 0));  // 将蓝色通道值放到目标像素的蓝色位置

            // 移动目标缓冲区的指针，指向下一个像素位置
            ++Dest;
            // 移动源图像的指针，指向下一个像素位置
            ++Source;
        }
        // 将目标指针移动到下一行
        DestRow += Buffer->Pitch;
        // 将源指针移动到上一行（因为位图数据是自底向上存储的）
        SourceRow += Bitmap->Pitch;
    }
}

internal void DrawBitMap(loaded_bitmap *Buffer,                              //
                         loaded_bitmap *Bitmap, real32 RealX, real32 RealY,  //
                         real32 CAlpha = 1.0f) {
    // 计算位图在缓冲区中绘制的像素对齐矩形坐标
    int32 MinX = RoundReal32ToInt32(RealX);  // 位图的左边界
    int32 MinY = RoundReal32ToInt32(RealY);  // 位图的上边界
    int32 MaxX = MinX + Bitmap->Width;       // 位图的右边界
    int32 MaxY = MinY + Bitmap->Height;      // 位图的下边界

    int32 SourceOffsetY = 0;
    int32 SourceOffsetX = 0;
    // 将计算的矩形坐标限制在缓冲区边界内
    if (MinX < 0) {
        SourceOffsetX = -MinX;
        MinX = 0;  // 防止越过缓冲区左边界
    }
    if (MinY < 0) {
        SourceOffsetY = -MinY;
        MinY = 0;  // 防止越过缓冲区上边界
    }
    if (MaxX > Buffer->Width) {
        MaxX = Buffer->Width;  // 防止越过缓冲区右边界
    }
    if (MaxY > Buffer->Height) {
        MaxY = Buffer->Height;  // 防止越过缓冲区下边界
    }

    // Bitmap->Pitch * (Bitmap->Height - 1)
    //  获取位图数据的指针
    //  注意：位图数据是从底部开始存储的，因此从最后一行开始读取
    uint8 *SourceRow = (uint8 *)Bitmap->Memory + Bitmap->Pitch * SourceOffsetY +
                       BITMAP_BYTES_PER_PIEXLE * SourceOffsetX;
    // 获取缓冲区内存的指针，从绘制起点(MinX, MinY)开始
    // 缓冲区的内存布局是线性的，因此需要根据每行的跨度(Pitch)和像素大小计算起始位置
    uint8 *DestRow =
        ((uint8 *)Buffer->Memory + MinX * BITMAP_BYTES_PER_PIEXLE + MinY * Buffer->Pitch);

    // 遍历裁剪后的矩形区域中的每一行
    for (int32 Y = MinY; Y < MaxY; ++Y) {
        uint32 *Dest = (uint32 *)DestRow;      // 目标缓冲区当前行的指针
        uint32 *Source = (uint32 *)SourceRow;  // 源位图当前行的指针

        // 遍历当前行的每一列
        // 遍历从 MinX 到 MaxX 的每个像素
        for (int32 X = MinX; X < MaxX; ++X) {
            v4 Texel = {// 获取源像素的红色通道值
                        CAlpha * (real32)((*Source >> 16) & 0xFF),
                        // 获取源像素的绿色通道值
                        CAlpha * (real32)((*Source >> 8) & 0xFF),
                        // 获取源像素的蓝色通道值
                        CAlpha * (real32)((*Source >> 0) & 0xFF),
                        // 获取源像素的Alpha通道值（范围0-255）
                        ((real32)((*Source >> 24) & 0xFF))};
            Texel = SRGB255ToLinear1(Texel);
            Texel *= CAlpha;

            v4 D = {// 获取目标像素的红色通道值
                    (real32)((*Dest >> 16) & 0xFF),
                    // 获取目标像素的绿色通道值
                    (real32)((*Dest >> 8) & 0xFF),
                    // 获取目标像素的蓝色通道值
                    (real32)((*Dest >> 0) & 0xFF),
                    // 获取目标像素的Alpha通道值
                    (real32)((*Dest >> 24) & 0xFF)};
            D = SRGB255ToLinear1(D);

            // 计算源和目标像素的Alpha值加权

            v4 Result = (1.0f - Texel.a) * D + Texel;

            Result = Linear1ToSRGB255(Result);

            // 将混合后的RGB值合并为一个32位整数并保存到目标像素中，经过四舍五入
            *Dest = (((uint32)(Result.a + 0.5f) << 24)  //
                     | ((uint32)(Result.r + 0.5f) << 16)  // 将红色通道值放到目标像素的红色位置
                     | ((uint32)(Result.g + 0.5f) << 8)  // 将绿色通道值放到目标像素的绿色位置
                     | ((uint32)(Result.b + 0.5f) << 0));  // 将蓝色通道值放到目标像素的蓝色位置

            // 移动目标缓冲区的指针，指向下一个像素位置
            ++Dest;
            // 移动源图像的指针，指向下一个像素位置
            ++Source;
        }
        // 将目标指针移动到下一行
        DestRow += Buffer->Pitch;
        // 将源指针移动到上一行（因为位图数据是自底向上存储的）
        SourceRow += Bitmap->Pitch;
    }
}

inline sprite_bound GetBoundFor(object_transform *ObjectTransform, v3 Offset, real32 Height) {
    sprite_bound SpriteBound;
    SpriteBound.ManualSort = ObjectTransform->ManualSort;
    SpriteBound.YMin = SpriteBound.YMax = ObjectTransform->OffsetP.y + Offset.y;
    SpriteBound.ChunkZ = ObjectTransform->ChunkZ;
    SpriteBound.ZMax = ObjectTransform->OffsetP.z + Offset.z;
    if (ObjectTransform->Upright) {
        SpriteBound.ZMax += 0.5f * Height;
    } else {
        SpriteBound.YMax += 0.5f * Height;
        SpriteBound.YMin += -0.5f * Height;
    }
    return SpriteBound;
}

// 清除渲染组中的所有内容，设置背景颜色
// 参数：
// - Group: 渲染组，包含要清除的渲染元素
// - Color: 要设置的清除颜色（背景颜色）
void Clear(render_group *Group, v4 Color) {  //
    Group->Commands->ClearColor = Color;
}

// 定义饱和度调整函数，向渲染组中添加一个饱和度渲染条目
void Saturation(render_group *Group, real32 Level, rectangle2 ScreenArea) {
    sprite_bound SortKey;
    SortKey.YMin = Real32Minimum;
    SortKey.YMax = Real32Maximum;
    SortKey.ZMax = Real32Minimum;
    // 向渲染组中推送一个饱和度渲染条目
    render_entry_saturation *Entry =
        PushRenderElement(Group, render_entry_saturation, SortKey, ScreenArea);

    // 如果条目推送成功，则设置饱和度值
    if (Entry) {
        Entry->Level = Level;  // 设置饱和度调整级别
    }
}

// 计算并返回渲染实体的基础位置 (单位：像素)
entity_basis_p_result GetRenderEntityBasisP(camera_transform *CameraTransform,
                                            object_transform *ObjectTransform, v3 OriginalP) {
    entity_basis_p_result Result{};  // 初始化返回结果

    v3 P = OriginalP + ObjectTransform->OffsetP;
    // v3 P = OriginalP.xyz + ObjectTransform->OffsetP;
    if (CameraTransform->Orthographic) {
        Result.P = CameraTransform->ScreenCenter + CameraTransform->MetersToPixels * P.xy;
        Result.SCale = CameraTransform->MetersToPixels;
        Result.Valid = true;
    } else {
        real32 OffsetZ = 0.0f;
        real32 DistanceAboveTarget = CameraTransform->DistanceAboveTarget;

        if (Global_Renderer_Camera_UsedDebug) {
            DistanceAboveTarget += Global_Renderer_Camera_DebugDistance;
        }
        // 计算目标点的Z轴距离
        real32 DistanceToPZ = DistanceAboveTarget - P.z;
        // 实体的Z坐标与相机的Z坐标差值

        // 近裁剪平面的距离
        real32 NearClipPlane = 0.2f;
        // 近裁剪平面距离（单位：像素）

        // 计算实体在屏幕上的原始XY坐标，考虑偏移量
        v3 RawXY = ToV3(P.xy, 1.0f);

        // 如果实体的Z坐标大于近裁剪平面的距离，进行投影计算
        if (DistanceToPZ > NearClipPlane) {
            // 使用透视投影将实体的XY坐标投影到屏幕上
            v3 ProjectedXY = (1.0f / DistanceToPZ) * CameraTransform->FocalLength * RawXY;
            // 屏幕上的位置
            Result.SCale = CameraTransform->MetersToPixels * ProjectedXY.z;
            // 将计算结果保存到返回的结果中
            Result.P = CameraTransform->ScreenCenter +
                       CameraTransform->MetersToPixels * ProjectedXY.xy +
                       v2{0.0f, Result.SCale * OffsetZ};

            // 计算得到的缩放比例
            Result.Valid = true;
            // 标记为有效结果
        }
    }

    // 返回计算后的实体位置
    return Result;
}

// 创建一个渲染条目，表示坐标系的渲染数据
// 参数：
// - Group: 渲染组，用于存储渲染条目
// - Origin: 坐标系的原点
// - XAxis: X轴方向
// - YAxis: Y轴方向
// - Texture: 坐标系的纹理贴图
// - NormapMap: 坐标系的法线贴图
// - Top: 顶部环境贴图
// - Middle: 中间环境贴图
// - Bottom: 底部环境贴图
void CoordinateSystem(render_group *Group, v2 Origin, v2 XAxis, v2 YAxis, v4 Color,
                      loaded_bitmap *Texture,    //
                      loaded_bitmap *NormapMap,  //
                      environment_map *Top,      //
                      environment_map *Middle,   //
                      environment_map *Bottom) {
    (void)Group;
    (void)Origin;
    (void)XAxis;
    (void)YAxis;
    (void)Color;
    (void)Texture;
    (void)NormapMap;
    (void)Top;
    (void)Middle;
    (void)Bottom;
#if 0
                                // 计算矩形的位置
    entity_basis_p_result Basis =
        GetRenderEntityBasisP(&Group->Transform,);
    if (Basis.Valid) {
        // 创建一个渲染条目并将其推入渲染组
        render_entry_coordinate_system *Entry =
            PushRenderElement(Group, render_entry_coordinate_system);

        // 如果成功创建条目，则设置其各项属性
        if (Entry) {
            Entry->Origin = Origin;        // 设置原点
            Entry->XAxis = XAxis;          // 设置X轴
            Entry->YAxis = YAxis;          // 设置Y轴
            Entry->Color = Color;          // 设置颜色
            Entry->Texture = Texture;      // 设置纹理贴图
            Entry->NormalMap = NormapMap;  // 设置法线贴图
            Entry->Top = Top;              // 设置顶部环境贴图
            Entry->Middle = Middle;        // 设置中间环境贴图
            Entry->Bottom = Bottom;        // 设置底部环境贴图
        }
    }
#endif
}

v2 UnprojectOld(render_group *RenderGroup, v2 ProjectedXY, real32 AtDistanceFromCamera) {
    v2 WorldXY = (AtDistanceFromCamera / RenderGroup->CameraTransform.FocalLength) * ProjectedXY;
    return WorldXY;
}

v3 Unproject(render_group *RenderGroup, object_transform *ObjectTransform, v2 PixelsXY) {
    camera_transform *Transform = &RenderGroup->CameraTransform;
    v2 UnprojectedXY = {};
    if (Transform->Orthographic) {
        UnprojectedXY = (1.0f / Transform->MetersToPixels) * (PixelsXY - Transform->ScreenCenter);
    } else {
        v2 A = (PixelsXY - Transform->ScreenCenter) * (1.0f / Transform->MetersToPixels);
        UnprojectedXY = ((Transform->DistanceAboveTarget - ObjectTransform->OffsetP.z) /
                         Transform->FocalLength) *
                        A;
    }
    v3 Result = ToV3(UnprojectedXY, ObjectTransform->OffsetP.z);
    Result -= ObjectTransform->OffsetP;
    return Result;
}

uint32 PushClipRect(render_group *Group, uint32 X, uint32 Y, uint32 W, uint32 H,
                    uint32 RenderTargetIndex) {
    uint32 Result = 0;
    uint32 Size = sizeof(render_entry_cliprect);
    push_buffer_result Push = PushBuffer(Group, 0, Size);
    if (Push.Header) {
        render_entry_cliprect *ClipRect = (render_entry_cliprect *)(Push.Header);
        Result = Group->Commands->ClipRectCount++;
        if (Group->Commands->LastRect) {
            Group->Commands->LastRect = Group->Commands->LastRect->Next = ClipRect;
        } else {
            Group->Commands->LastRect = Group->Commands->FirstRect = ClipRect;
        }
        ClipRect->Next = 0;
        ClipRect->Rect.MinX = X;
        ClipRect->Rect.MinY = Y;
        ClipRect->Rect.MaxX = X + W;
        ClipRect->Rect.MaxY = Y + H;
        ClipRect->RenderTargetIndex = RenderTargetIndex;
        if (Group->Commands->MaxRenderTargetIndex < RenderTargetIndex) {
            Group->Commands->MaxRenderTargetIndex = RenderTargetIndex;
        }
    }
    return Result;
}

void PushBlendRenderTarget(render_group *Group, real32 Alpha, uint32 SourceRenderTargetIndex) {
    PushSortBarrier(Group, false);
    sprite_bound SortKey = {};
    rectangle2 ScreenArea = {};
    render_entry_blend_render_target *Blend =
        PushRenderElement(Group, render_entry_blend_render_target, SortKey, ScreenArea);
    Blend->SourceTargetIndex = SourceRenderTargetIndex;
    Blend->Alpha = Alpha;
    PushSortBarrier(Group, false);
}

uint32 PushClipRect(render_group *Group, object_transform *ObjectTransform, v3 Offset, v2 Dim,
                    uint32 RenderTargetIndex) {
    uint32 Result = 0;
    v3 OriginalP = {Offset - ToV3(0.5f * Dim, 0)};
    entity_basis_p_result Basis =
        GetRenderEntityBasisP(&Group->CameraTransform, ObjectTransform, OriginalP);
    if (Basis.Valid) {
        v2 P = Basis.P;
        v2 SCaleDim = Basis.SCale * Dim;
        Result = PushClipRect(Group, RoundReal32ToInt32(P.x),  //
                              RoundReal32ToInt32(P.y),         //
                              RoundReal32ToInt32(SCaleDim.x),  //
                              RoundReal32ToInt32(SCaleDim.y), RenderTargetIndex);
    }
    return Result;
}

uint32 PushClipRect(render_group *Group, object_transform *ObjectTransform, rectangle2 Rectangle,
                    real32 Z, uint32 RenderTargetIndex) {
    uint32 Result = PushClipRect(Group, ObjectTransform, ToV3(GetCenter(Rectangle), Z),
                                 GetDim(Rectangle), RenderTargetIndex);
    return Result;
}

rectangle2 GetCameraRectangleAtDistance(render_group *RenderGroup, real32 DistanceFromCamera) {
    v2 RawXY = UnprojectOld(RenderGroup, RenderGroup->MonitorHalfDimInMeters, DistanceFromCamera);
    rectangle2 Result = RectCenterHalfDim(v2{0, 0}, RawXY);
    return Result;
}

rectangle2 GetCameraRectangleAtTarget(render_group *RenderGroup) {
    rectangle2 Result =
        GetCameraRectangleAtDistance(RenderGroup, RenderGroup->CameraTransform.DistanceAboveTarget);
    return Result;
}

void PushBitmap(render_group *Group, object_transform *ObjectTransform, bitmap_id ID, real32 Height,
                v3 Offset, v4 Color, real32 CAlign, v2 XAxis, v2 YAxis) {
    loaded_bitmap *Bitmap = GetBitmap(Group->Assets, ID, Group->GenerationID);
    if (Group->RendersInBackground && !Bitmap) {
        LoadBitmap(Group->Assets, ID, true);
        Bitmap = GetBitmap(Group->Assets, ID, Group->GenerationID);
    }
    if (Bitmap) {
        PushBitmap(Group, ObjectTransform, Bitmap, Height, Offset, Color, CAlign, XAxis, YAxis);
    } else {
        Assert(!Group->RendersInBackground);
        LoadBitmap(Group->Assets, ID, false);
        ++Group->MissingResourceCount;
    }
}
loaded_font *PushFont(render_group *Group, font_id ID) {
    loaded_font *Font = GetFont(Group->Assets, ID, Group->GenerationID);
    if (Font) {
    } else {
        Assert(!Group->RendersInBackground);
        LoadFont(Group->Assets, ID, false);
        ++Group->MissingResourceCount;
    }
    return Font;
}

used_bitmap_dim GetUsedBitmapDim(render_group *Group, object_transform *ObjectTransform,
                                 loaded_bitmap *Bitmap, real32 Height, v3 Offset, real32 CAlign,
                                 v2 XAxis, v2 YAxis) {
    used_bitmap_dim Dim;
    // 如果需要位图的渲染处理，取消下面的注释并实现该功能
    Dim.Size = v2{Height * Bitmap->WidthOverHeight, Height};
    Dim.Align = CAlign * Hadamard(Bitmap->AlignPrecentage, Dim.Size);
    Dim.P.z = Offset.z;
    Dim.P.xy = Offset.xy - Dim.Align.x * XAxis - Dim.Align.y * YAxis;
    Dim.Basis = GetRenderEntityBasisP(&Group->CameraTransform, ObjectTransform, Dim.P);
    return Dim;
}

v4 StoreColor(object_transform *Transform, v4 Source) {
    v4 Dest;
    v4 t = Transform->tColor;
    v4 C = Transform->Color;
    Dest.a = Lerp(Source.a, t.a, C.a);
    Dest.r = Dest.a * Lerp(Source.r, t.r, C.r);
    Dest.g = Dest.a * Lerp(Source.g, t.g, C.g);
    Dest.b = Dest.a * Lerp(Source.b, t.b, C.b);
    return Dest;
}

void PushBitmap(render_group *Group, object_transform *ObjectTransform, loaded_bitmap *Bitmap,
                real32 Height, v3 Offset, v4 Color, real32 CAlign, v2 XAxis, v2 YAxis) {
    used_bitmap_dim Dim =
        GetUsedBitmapDim(Group, ObjectTransform, Bitmap, Height, Offset, CAlign, XAxis, YAxis);
    if (Dim.Basis.Valid && Bitmap->Memory) {
        v2 Size = Dim.Basis.SCale * Dim.Size;
        sprite_bound SpriteBound = GetBoundFor(ObjectTransform, Offset, Height);
        rectangle2 ScreenArea = RectMinDim(Dim.Basis.P, Size);
        // 获取组中下一个可用元素的指针，并将元素计数加一。
        render_entry_bitmap *Entry =
            PushRenderElement(Group, render_entry_bitmap, SpriteBound, ScreenArea);

        if (Entry) {
            // 将位图分配给当前元素，这代表该元素的视觉表现。
            Entry->Bitmap = Bitmap;

            // 设置Piece的颜色属性
            Entry->PremulColor = StoreColor(ObjectTransform, Color);
            Entry->XAxis = Size.x * XAxis;
            Entry->YAxis = Size.y * YAxis;
            Entry->P = Dim.Basis.P;
        }
    }
}

// PushBitmap函数将一个位图（Bitmap）推送到实体可视组（Group）
// 通过设置偏移（Offset）、偏移Z（OffsetZ）、对齐（Align）等参数来定义图形的位置、尺寸和颜色。
void PushBitmap(render_group *Group, object_transform *ObjectTransform, loaded_bitmap *Bitmap,
                real32 Height, v3 Offset, v4 Color, real32 CAlign) {
    used_bitmap_dim Dim = GetUsedBitmapDim(Group, ObjectTransform, Bitmap, Height, Offset, CAlign);
    if (Dim.Basis.Valid && Bitmap->Memory) {
        v2 Size = Dim.Basis.SCale * Dim.Size;
        sprite_bound SpriteBound = GetBoundFor(ObjectTransform, Offset, Height);
        rectangle2 ScreenArea = RectMinDim(Dim.Basis.P, Size);

        // 获取组中下一个可用元素的指针，并将元素计数加一。
        render_entry_bitmap *Entry =
            PushRenderElement(Group, render_entry_bitmap, SpriteBound, ScreenArea);

        if (Entry) {
            // 将位图分配给当前元素，这代表该元素的视觉表现。
            Entry->Bitmap = Bitmap;

            // 设置Piece的颜色属性
            Entry->PremulColor = StoreColor(ObjectTransform, Color);
            Entry->XAxis = v2{Size.x, 0};
            Entry->YAxis = v2{0, Size.y};
            Entry->P = Dim.Basis.P;
        }
    }
}

// PushRect函数将一个矩形（Rect）推送到实体可视组（Group）
// 通过设置偏移（Offset）、偏移Z（OffsetZ）、矩形尺寸（Dim）、颜色（R, G,
// B）等参数来定义矩形的位置、尺寸和颜色。
void PushRect(render_group *Group, object_transform *ObjectTransform, v3 Offset,  //
              v2 Dim, v4 Color) {
    v3 P = Offset - ToV3(0.5f * Dim, 0.0f);
    // 计算矩形的位置
    entity_basis_p_result Basis =
        GetRenderEntityBasisP(&Group->CameraTransform, ObjectTransform, P);
    if (Basis.Valid) {
        v2 ScaleDim = Basis.SCale * Dim;
        sprite_bound SpriteBound = GetBoundFor(ObjectTransform, Offset, Dim.y);
        rectangle2 ScreenArea = RectMinDim(Basis.P, ScaleDim);
        // 获取组中下一个可用元素的指针，并将元素计数加一。
        render_entry_rectangle *Rect =
            PushRenderElement(Group, render_entry_rectangle, SpriteBound, ScreenArea);

        if (Rect) {
            Rect->P = Basis.P;
            // 设置Piece的颜色属性
            Rect->PremulColor = StoreColor(ObjectTransform, Color);

            // 设置Piece的尺寸属性
            Rect->Dim = Basis.SCale * Dim;  // 设置Piece的尺寸（例如宽度和高度或其他维度）
        }
    }
}

void PushRect(render_group *Group, object_transform *ObjectTransform, rectangle2 Rectangle,
              real32 Z, v4 Color) {
    PushRect(Group, ObjectTransform, ToV3(GetCenter(Rectangle), Z),  //
             GetDim(Rectangle), Color);
}

void PushRectOutline(render_group *Group, object_transform *ObjectTransform, rectangle2 Rectangle,
                     real32 Z, v4 Color, real32 Thickness) {
    PushRectOutline(Group, ObjectTransform, ToV3(GetCenter(Rectangle), Z),  //
                    GetDim(Rectangle), Color, Thickness);
}

void PushRectOutline(render_group *Group, object_transform *ObjectTransform, v3 Offset, v2 Dim,
                     v4 Color, real32 Thickness) {
    // 绘制矩形的上下边缘，分别在 Offset 上下偏移半个矩形高度，宽度为 Dim.x，厚度为
    // Thickness
    PushRect(Group, ObjectTransform, Offset - v3{0, 0.5f * Dim.y, 0},  //
             v2{Dim.x - Thickness - 0.01f, Thickness}, Color);         // 上边缘
    PushRect(Group, ObjectTransform, Offset + v3{0, 0.5f * Dim.y, 0},  //
             v2{Dim.x - Thickness - 0.01f, Thickness}, Color);         // 下边缘

    // 绘制矩形的左右边缘，分别在 Offset 左右偏移半个矩形宽度，高度为 Dim.y，厚度为
    // Thickness
    PushRect(Group, ObjectTransform, Offset - v3{0.5f * Dim.x, 0, 0},  //
             v2{Thickness, Dim.y + Thickness}, Color);                 // 左边缘
    PushRect(Group, ObjectTransform, Offset + v3{0.5f * Dim.x, 0, 0},  //
             v2{Thickness, Dim.y + Thickness}, Color);                 // 右边缘
}

void *PushRenderElement_(render_group *Group, uint32 Size, render_group_entry_type Type,
                         sprite_bound SortKey, rectangle2 ScreenArea) {
    void *Result = 0;
    game_render_commands *Commands = Group->Commands;
    // 增加 header 的大小到实际的元素大小
    Size += sizeof(render_group_entry_header);
    push_buffer_result Push = PushBuffer(Group, 1, Size);
    if (Push.SortEntry) {
        // 获取当前 push buffer 的末尾位置，准备写入新的渲染元素
        render_group_entry_header *Header = Push.Header;
        // 设置 header 的类型为给定的类型
        Header->Type = Type;
        Header->ClipRectIndex = SafeTruncateUInt16(Group->CurrentClipRectIndex);
#if GAME_SLOW
        Header->DebugTag = Group->DebugTag;
#endif
        // 返回元素数据的指针（即 header 后面的空间）
        Result = (uint8 *)Header + sizeof(*Header);
        sort_sprite_bound *Entry = Push.SortEntry;
        Entry->SortKey = SortKey;
        Entry->Offset = (uint32)((uint8 *)Header - Commands->PushBufferBase);
        Assert(Entry->Offset != 0);
        Entry->FirstEdgeWithMeAsFront = 0;
        Entry->Flags = 0;
        Entry->ScreenArea = ScreenArea;
        // 更新 PushBuffer 的大小
        if (Group->FirstAggregate) {
            if (Group->FirstAggregate == Push.SortEntry) {
                Group->AggregateBound = SortKey;
            } else if (IsZSprite(Group->AggregateBound)) {
                Assert(IsZSprite(SortKey));
                Group->AggregateBound.YMin = Minimum(Group->AggregateBound.YMin, SortKey.YMin);
                Group->AggregateBound.YMax = Maximum(Group->AggregateBound.YMax, SortKey.YMax);
                Group->AggregateBound.ZMax = Maximum(Group->AggregateBound.ZMax, SortKey.ZMax);
            } else {
                Assert(!IsZSprite(SortKey));
                // Group->AggregateBound.YMin = Minimum(Group->AggregateBound.YMin, SortKey.YMin);
                // Group->AggregateBound.YMax = Maximum(Group->AggregateBound.YMax, SortKey.YMax);
                Group->AggregateBound.ZMax = Maximum(Group->AggregateBound.ZMax, SortKey.ZMax);
            }
        }
    } else {
        // 如果没有足够的空间，触发错误路径
        InvalidCodePath;
    }

    return Result;
}

bool32 AllResourcePresent(render_group *Group) {  //
    bool32 Result = (Group->MissingResourceCount == 0);
    return Result;
}
void BeginAggregateSortKey(render_group *RenderGroup) {
    Assert(!RenderGroup->FirstAggregate);
    RenderGroup->IsAggregating = true;
    game_render_commands *Commands = RenderGroup->Commands;
    RenderGroup->FirstAggregate = GetSortEntries(Commands) + Commands->SortEntryCount;
    RenderGroup->AggregateBound.YMin = Real32Maximum;
    RenderGroup->AggregateBound.YMax = Real32Minimum;
    RenderGroup->AggregateBound.ZMax = Real32Minimum;
}

void EndAggregateSortKey(render_group *RenderGroup) {
    Assert(RenderGroup->FirstAggregate);
    RenderGroup->IsAggregating = false;
    game_render_commands *Commands = RenderGroup->Commands;
    sort_sprite_bound *OnePastLastEntry =
        (sort_sprite_bound *)(GetSortEntries(Commands) + Commands->SortEntryCount);
    for (sort_sprite_bound *Entry = RenderGroup->FirstAggregate; Entry != OnePastLastEntry;
         ++Entry) {
        Entry->SortKey = RenderGroup->AggregateBound;
    }
    RenderGroup->FirstAggregate = 0;
}